home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 365_02 / vcmd.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  18KB  |  976 lines

  1. /* vcmd.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the functions that handle VI commands */
  12.  
  13.  
  14. #include "config.h"
  15. #include "ctype.h"
  16. #include "vi.h"
  17. #if MSDOS
  18. # include <process.h>
  19. # include <string.h>
  20. #endif
  21. #if TOS
  22. # include <osbind.h>
  23. # include <string.h>
  24. #endif
  25. #if OSK
  26. # include <stdio.h>
  27. #endif
  28.  
  29.  
  30. /* This function puts the editor in EX mode */
  31. MARK v_quit()
  32. {
  33.     move(LINES - 1, 0);
  34.     mode = MODE_EX;
  35.     return cursor;
  36. }
  37.  
  38. /* This function causes the screen to be redrawn */
  39. MARK v_redraw()
  40. {
  41.     redraw(MARK_UNSET, FALSE);
  42.     return cursor;
  43. }
  44.  
  45. /* This function executes a string of EX commands, and waits for a user keystroke
  46.  * before returning to the VI screen.  If that keystroke is another ':', then
  47.  * another EX command is read and executed.
  48.  */
  49. /*ARGSUSED*/
  50. MARK v_1ex(m, text)
  51.     MARK    m;    /* the current line */
  52.     char    *text;    /* the first command to execute */
  53. {
  54.     /* run the command.  be careful about modes & output */
  55.     exwrote = (mode == MODE_COLON);
  56.     doexcmd(text);
  57.     exrefresh();
  58.  
  59.     /* if mode is no longer MODE_VI, then we should quit right away! */
  60.     if (mode != MODE_VI && mode != MODE_COLON)
  61.         return cursor;
  62.  
  63.     /* The command did some output.  Wait for a keystoke. */
  64.     if (exwrote)
  65.     {
  66.         mode = MODE_VI;    
  67.         msg("[Hit <RETURN> to continue]");
  68.         if (getkey(0) == ':')
  69.         {    mode = MODE_COLON;
  70.             addch('\n');
  71.         }
  72.         else
  73.             redraw(MARK_UNSET, FALSE);
  74.     }
  75.  
  76.     return cursor;
  77. }
  78.  
  79. /* This function undoes the last change */
  80. /*ARGSUSED*/
  81. MARK v_undo(m)
  82.     MARK    m;    /* (ignored) */
  83. {
  84.     if (undo())
  85.     {
  86.         redraw(MARK_UNSET, FALSE);
  87.     }
  88.     return cursor;
  89. }
  90.  
  91. /* This function deletes the character(s) that the cursor is on */
  92. MARK v_xchar(m, cnt, cmd)
  93.     MARK    m;    /* where to start deletions */
  94.     long    cnt;    /* number of chars to delete */
  95.     int    cmd;    /* either 'x' or 'X' */
  96. {
  97.     DEFAULT(1);
  98.  
  99.     /* for 'X', adjust so chars are deleted *BEFORE* cursor */
  100.     if (cmd == 'X')
  101.     {
  102.         if (markidx(m) < cnt)
  103.             return MARK_UNSET;
  104.         m -= cnt;
  105.     }
  106.  
  107.     /* make sure we don't try to delete more thars than there are */
  108.     pfetch(markline(m));
  109.     if (markidx(m + cnt) > plen)
  110.     {
  111.         cnt = plen - markidx(m);
  112.     }
  113.     if (cnt == 0L)
  114.     {
  115.         return MARK_UNSET;
  116.     }
  117.  
  118.     /* do it */
  119.     ChangeText
  120.     {
  121.         cut(m, m + cnt);
  122.         delete(m, m + cnt);
  123.     }
  124.     return m;
  125. }
  126.  
  127. /* This function defines a mark */
  128. /*ARGSUSED*/
  129. MARK v_mark(m, count, key)
  130.     MARK    m;    /* where the mark will be */
  131.     long    count;    /* (ignored) */
  132.     int    key;    /* the ASCII label of the mark */
  133. {
  134.     if (key < 'a' || key > 'z')
  135.     {
  136.         msg("Marks must be from a to z");
  137.     }
  138.     else
  139.     {
  140.         mark[key - 'a'] = m;
  141.     }
  142.     return m;
  143. }
  144.  
  145. /* This function toggles upper & lower case letters */
  146. MARK v_ulcase(m, cnt)
  147.     MARK    m;    /* where to make the change */
  148.     long    cnt;    /* number of chars to flip */
  149. {
  150.     REG char     *pos;
  151.     REG int        j;
  152.  
  153.     DEFAULT(1);
  154.  
  155.     /* fetch the current version of the line */
  156.     pfetch(markline(m));
  157.  
  158.     /* for each position in the line */
  159.     for (j = 0, pos = &ptext[markidx(m)]; j < cnt && *pos; j++, pos++)
  160.     {
  161.         if (isupper(*pos))
  162.         {
  163.             tmpblk.c[j] = tolower(*pos);
  164.         }
  165.         else
  166.         {
  167.             tmpblk.c[j] = toupper(*pos);
  168.         }
  169.     }
  170.  
  171.     /* if the new text is different from the old, then change it */
  172.     if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
  173.     {
  174.         ChangeText
  175.         {
  176.             tmpblk.c[j] = '\0';
  177.             change(m, m + j, tmpblk.c);
  178.         }
  179.     }
  180.  
  181.     return m + j;
  182. }
  183.  
  184.  
  185. MARK v_replace(m, cnt, key)
  186.     MARK    m;    /* first char to be replaced */
  187.     long    cnt;    /* number of chars to replace */
  188.     int    key;    /* what to replace them with */
  189. {
  190.     REG char    *text;
  191.     REG int        i;
  192.  
  193.     DEFAULT(1);
  194.  
  195.     /* map ^M to '\n' */
  196.     if (key == '\r')
  197.     {
  198.         key = '\n';
  199.     }
  200.  
  201.     /* make sure the resulting line isn't too long */
  202.     if (cnt > BLKSIZE - 2 - markidx(m))
  203.     {
  204.         cnt = BLKSIZE - 2 - markidx(m);
  205.     }
  206.  
  207.     /* build a string of the desired character with the desired length */
  208.     for (text = tmpblk.c, i = cnt; i > 0; i--)
  209.     {
  210.         *text++ = key;
  211.     }
  212.     *text = '\0';
  213.  
  214.     /* make sure cnt doesn't extend past EOL */
  215.     pfetch(markline(m));
  216.     key = markidx(m);
  217.     if (key + cnt > plen)
  218.     {
  219.         cnt = plen - key;
  220.     }
  221.  
  222.     /* do the replacement */
  223.     ChangeText
  224.     {
  225.         change(m, m + cnt, tmpblk.c);
  226.     }
  227.  
  228.     if (*tmpblk.c == '\n')
  229.     {
  230.         return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
  231.     }
  232.     else
  233.     {
  234.         return m + cnt - 1;
  235.     }
  236. }
  237.  
  238. MARK v_overtype(m)
  239.     MARK        m;    /* where to start overtyping */
  240. {
  241.     MARK        end;    /* end of a substitution */
  242.     static long    width;    /* width of a single-line replace */
  243.  
  244.     /* the "doingdot" version of replace is really a substitution */
  245.     if (doingdot)
  246.     {
  247.         /* was the last one really repeatable? */
  248.         if (width < 0)
  249.         {
  250.             msg("Can't repeat a multi-line overtype command");
  251.             return MARK_UNSET;
  252.         }
  253.  
  254.         /* replacing nothing by nothing?  Don't bother */
  255.         if (width == 0)
  256.         {
  257.             return m;
  258.         }
  259.  
  260.         /* replace some chars by repeated text */
  261.         return v_subst(m, width);
  262.     }
  263.  
  264.     /* Normally, we input starting here, in replace mode */
  265.     ChangeText
  266.     {
  267.         end = input(m, m, WHEN_VIREP, FALSE);
  268.     }
  269.  
  270.     /* if we ended on the same line we started on, then this
  271.      * overtype is repeatable via the dot key.
  272.      */
  273.     if (markline(end) == markline(m) && end >= m - 1L)
  274.     {
  275.         width = end - m + 1L;
  276.     }
  277.     else /* it isn't repeatable */
  278.     {
  279.         width = -1L;
  280.     }
  281.  
  282.     return end;
  283. }
  284.  
  285.  
  286. /* This function selects which cut buffer to use */
  287. /*ARGSUSED*/
  288. MARK v_selcut(m, cnt, key)
  289.     MARK    m;
  290.     long    cnt;
  291.     int    key;
  292. {
  293.     cutname(key);
  294.     return m;
  295. }
  296.  
  297. /* This function pastes text from a cut buffer */
  298. /*ARGSUSED*/
  299. MARK v_paste(m, cnt, cmd)
  300.     MARK    m;    /* where to paste the text */
  301.     long    cnt;    /* (ignored) */
  302.     int    cmd;    /* either 'p' or 'P' */
  303. {
  304.     MARK    dest;
  305.  
  306.     ChangeText
  307.     {
  308.         /* paste the text, and find out where it ends */
  309.         dest = paste(m, cmd == 'p', TRUE);
  310.  
  311.         /* was that a line-mode paste? */
  312.         if (dest && markline(dest) != markline(m))
  313.         {
  314.             /* line-mode pastes leave the cursor at the front
  315.              * of the first pasted line.
  316.              */
  317.             dest = m;
  318.             if (cmd == 'p')
  319.             {
  320.                 dest += BLKSIZE;
  321.             }
  322.             force_flags |= FRNT;
  323.         }
  324.     }
  325.     return dest;
  326. }
  327.  
  328. /* This function yanks text into a cut buffer */
  329. MARK v_yank(m, n)
  330.     MARK    m, n;    /* range of text to yank */
  331. {
  332.     cut(m, n);
  333.     return m;
  334. }
  335.  
  336. /* This function deletes a range of text */
  337. MARK v_delete(m, n)
  338.     MARK    m, n;    /* range of text to delete */
  339. {
  340.     /* illegal to try and delete nothing */
  341.     if (n <= m)
  342.     {
  343.         return MARK_UNSET;
  344.     }
  345.  
  346.     /* Do it */
  347.     ChangeText
  348.     {
  349.         cut(m, n);
  350.         delete(m, n);
  351.     }
  352.     return m;
  353. }
  354.  
  355.  
  356. /* This starts input mode without deleting anything */
  357. MARK v_insert(m, cnt, key)
  358.     MARK    m;    /* where to start (sort of) */
  359.     long    cnt;    /* repeat how many times? */
  360.     int    key;    /* what command is this for? {a,A,i,I,o,O} */
  361. {
  362.     int    wasdot;
  363.     long    reps;
  364.     int    above;    /* boolean: new line going above old line? */
  365.  
  366.     DEFAULT(1);
  367.  
  368.     ChangeText
  369.     {
  370.         /* tweak the insertion point, based on command key */
  371.         above = FALSE;
  372.         switch (key)
  373.         {
  374.           case 'i':
  375.             break;
  376.  
  377.           case 'a':
  378.             pfetch(markline(m));
  379.             if (plen > 0)
  380.             {
  381.                 m++;
  382.             }
  383.             break;
  384.  
  385.           case 'I':
  386.             m = m_front(m, 1L);
  387.             break;
  388.  
  389.           case 'A':
  390.             pfetch(markline(m));
  391.             m = (m & ~(BLKSIZE - 1)) + plen;
  392.             break;
  393.  
  394.           case 'O':
  395.             m &= ~(BLKSIZE - 1);
  396.             add(m, "\n");
  397.             above = TRUE;
  398.             break;
  399.  
  400.           case 'o':
  401.             m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
  402.             add(m, "\n");
  403.             break;
  404.         }
  405.  
  406.         /* insert the same text once or more */
  407.         for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
  408.         {
  409.             m = input(m, m, WHEN_VIINP, above) + 1;
  410.         }
  411.         if (markidx(m) > 0)
  412.         {
  413.             m--;
  414.         }
  415.  
  416.         doingdot = wasdot;
  417.     }
  418.  
  419. #ifndef CRUNCH
  420. # ifndef NO_EXTENSIONS
  421.     if (key == 'i' && *o_inputmode && mode == MODE_VI)
  422.     {
  423.         msg("Now in command mode!  To return to input mode, hit <i>");
  424.     }
  425. # endif
  426. #endif
  427.  
  428.     return m;
  429. }
  430.  
  431. /* This starts input mode with some text deleted */
  432. MARK v_change(m, n)
  433.     MARK    m, n;    /* the range of text to change */
  434. {
  435.     int    lnmode;    /* is this a line-mode change? */
  436.  
  437.     /* swap them if they're in reverse order */
  438.     if (m > n)
  439.     {
  440.         MARK    tmp;
  441.         t